package com.e1xp.deport_management_system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.e1xp.deport_management_system.entity.Io;
import com.e1xp.deport_management_system.entity.Order;
import com.e1xp.deport_management_system.entity.OrderProduct;
import com.e1xp.deport_management_system.entity.Product;
import com.e1xp.deport_management_system.exception.CustomException;
import com.e1xp.deport_management_system.exception.CustomExceptionType;
import com.e1xp.deport_management_system.mapper.IoMapper;
import com.e1xp.deport_management_system.mapper.OrderMapper;
import com.e1xp.deport_management_system.mapper.OrderProductMapper;
import com.e1xp.deport_management_system.mapper.ProductMapper;
import com.e1xp.deport_management_system.service.IOrderService;
import com.e1xp.deport_management_system.service.IProductService;
import com.e1xp.deport_management_system.service.IUserService;
import com.e1xp.deport_management_system.utils.AddOrderProductWrapper;
import com.e1xp.deport_management_system.utils.PickRack;
import com.e1xp.deport_management_system.utils.PickWrapper;
import com.e1xp.deport_management_system.utils.PickedProduct;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.SessionAttribute;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author E1xP
 * @since 2021-04-09
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Resource
    OrderMapper orderMapper;

    @Resource
    IUserService userService;

    @Resource
    IoMapper ioMapper;

    @Resource
    IProductService productService;

    @Resource
    ProductMapper productMapper;

    @Resource
    OrderProductMapper orderProductMapper;

    /**
     * 查询未完成订单
     *
     * @param instanceId 实例id
     * @return int 未完成订单数
     */
    @Override
    public long getUnFinishCount(long instanceId) {
        return orderMapper.getUnFinishCount(instanceId);
    }

    /**
     * 获取最近count条数的未完成订单
     *
     * @param count      获取数量
     * @param instanceId 实例id
     * @return List Order列表
     */
    @Override
    public List<Order> getRecent(long instanceId, int count) {
        if (count <= 0)
            return null;
        else
            return orderMapper.getRecent(count, instanceId);
    }

    /**
     * 获取所有订单信息
     *
     * @param instanceId 实例id
     * @return List Order列表
     */
    @Override
    public List<Order> getList(long instanceId) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("instance_id", instanceId);
        queryWrapper.orderByDesc("order_time");
        return orderMapper.selectList(queryWrapper);
    }

    /**
     * 用于添加订单
     *
     * @param instanceId       实例id
     * @param order            订单实体
     * @param orderProductList 订单-产品实体列表
     * @throws CustomException 当找不到该实例，订单信息不完整，商品代码不存在时抛出该异常
     */
    @Override
    public void add(long instanceId, Order order, List<OrderProduct> orderProductList) throws CustomException {
        if (!userService.isInstance(instanceId)) {
            //添加
            throw new CustomException(CustomExceptionType.INSTANCE_NOT_FOUND_ERROR, "找不到该实例");
        }
        if (order.getOrderLocation() == null ||
                order.getOrderLocation().isEmpty() ||
                order.getOrderUser() == null ||
                order.getOrderUser().isEmpty() ||
                order.getOrderPhone() == null ||
                order.getOrderPhone().isEmpty()) {
            //校验数据
            throw new CustomException(CustomExceptionType.USER_INPUT_ERROR, "订单信息不完整");
        }
        //设置数据
        order.setInstanceId(instanceId);
        order.setOrderTime(LocalDateTime.now());//设置时间
        order.setStats(0);//设置状态
        order.setSendTime(null);
        order.setPrice(0.0);
        //将Order插入数据库
        orderMapper.insert(order);
        //获取传入商品对应实体
        Map<Long, Product> productMap = productService.getListFromId(instanceId, orderProductList.stream().map(OrderProduct::getProductId).collect(Collectors.toList()));
        if (productMap.size() != orderProductList.size()) {
            //若返还Map中大小与传入不同，存在无对应商品
            throw new CustomException(CustomExceptionType.PRODUCT_NOT_FOUND_ERROR, "商品代码不存在");
        }
        double sum = 0.0;
        for (OrderProduct item : orderProductList) {
            if (productMap.get(item.getProductId()).getUnsell() - item.getCount() < 0) {
                //商品数量不足
                throw new CustomException(CustomExceptionType.PRODUCT_NOT_ENOUGH, "商品数量不足");
            }
            productMap.get(item.getProductId()).setUnsell(productMap.get(item.getProductId()).getUnsell() - item.getCount());//修改unsell字段
            //设置OrderProduct数据
            double price = item.getCount() * productMap.get(item.getProductId()).getPrice();
            sum += price;
            item.setOrderId(order.getId());
            item.setPrice(price);
            item.setInstanceId(instanceId);
            item.setStats(1);
        }
        //更新数据
        ArrayList<Product> productList = new ArrayList<>(productMap.values());
        productMapper.updateList(productList);
        order.setPrice(sum);
        orderMapper.updateById(order);
        orderProductMapper.addList(orderProductList);
    }

    /**
     * 获取订单实体
     *
     * @param instanceId 实例id
     * @param orderId    订单id
     * @return Order实体
     */
    @Override
    public Order get(long instanceId, long orderId) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("instance_id", instanceId)
                .eq("id", orderId);
        return orderMapper.selectOne(queryWrapper);
    }

    /**
     * 获取订单的上商品条目
     *
     * @param instanceId 实例id
     * @param orderId    订单id
     * @return List Map商品条目
     */
    @Override
    public List<Map<String, String>> getOrderProductList(long instanceId, long orderId) {
        return orderMapper.getProductList(instanceId, orderId);
    }

    /**
     * 用于开始拣货
     *
     * @param instanceId 实例id
     * @param orderId    订单id
     * @param userId     用户id
     * @throws CustomException 当实例不存在，订单不存在时抛出该异常
     */
    @Override
    public void pick(long instanceId, long orderId, long userId) throws CustomException {
        if (!userService.isInstance(instanceId)) {
            //实例不存在
            throw new CustomException(CustomExceptionType.INSTANCE_NOT_FOUND_ERROR, "找不到该实例");
        }
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            //若订单不存在
            throw new CustomException(CustomExceptionType.ORDER_NOT_FOUND_ERROR, "找不到该用户");
        }
        order.setStats(1);
        order.setOperator(userId);
        orderMapper.updateById(order);
    }

    /**
     * 用于更新订单
     *
     * @param instanceId 实例id
     * @param order      订单实体
     * @throws CustomException 当订单数据不完整时，抛出该异常
     */
    @Override
    public void updateOrder(long instanceId, Order order) throws CustomException {
        if (order.getId() == null ||
                order.getOrderLocation() == null ||
                order.getOrderLocation().isEmpty() ||
                order.getOrderUser() == null ||
                order.getOrderUser().isEmpty() ||
                order.getOrderPhone() == null ||
                order.getOrderPhone().isEmpty()) {
            //校验数据
            throw new CustomException(CustomExceptionType.USER_INPUT_ERROR, "订单信息不完整");
        }
        order.setInstanceId(instanceId);
        orderMapper.updateById(order);
    }

    /**
     * 获取特定用户的待拣货订单
     *
     * @param instanceId 实例id
     * @param userId     用户id
     * @return List Order列表
     */
    @Override
    public List<Order> getPickingOrder(long instanceId, long userId) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("instance_id", instanceId)
                .eq("operator", userId)
                .eq("stats", 1);
        return orderMapper.selectList(queryWrapper);
    }

    /**
     * 用于获取订单的未完成拣货商品
     *
     * @param orderId 订单id
     * @return List Product列表
     */
    @Override
    public List<Map<String, String>> toPickProductList(long orderId) {
        return orderMapper.getToPickProduct(orderId);
    }

    /**
     * 用于获取待处理订单
     *
     * @param instanceId 实例id
     * @return List Order列表
     */
    @Override
    public List<Order> getPendingOrderList(long instanceId) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("instance_id", instanceId)
                .eq("stats", 0);
        return orderMapper.selectList(queryWrapper);
    }

    /**
     * 用于获取拣货列表商品与货架信息
     *
     * @param instanceId 实例id
     * @param orderId    订单id
     * @return Map
     */
    @Override
    public Map<String, Object> getPickingData(long instanceId, long orderId) {
        Map<String, Object> resultMap = new HashMap<>();
        //用于获取待拣货产品列表
        List<Map<String, String>> productList = toPickProductList(orderId);
        List<Map<String, String>> productSelector = new ArrayList<>();
        for (Map<String, String> item : productList) {
            Map<String, String> map = new HashMap<>();
            map.put("id", String.valueOf(item.get("productId")));
            map.put("text", String.valueOf(item.get("productId")) + " " + item.get("name") + " 仍需:" + String.valueOf(item.get("count")) + "个");
            productSelector.add(map);
        }
        resultMap.put("productList", productSelector);
        //货架信息
        List<PickRack> pickRackList = orderMapper.getPickRack(orderId);
        Map<String, List<PickRack>> pickRackMap = pickRackList.stream().collect(Collectors.groupingBy(PickRack::getProductId));
        resultMap.putAll(pickRackMap);
        return resultMap;
    }

    /**
     * 获取待发货订单
     *
     * @param instanceId 实例id
     * @return List Order列表
     */
    @Override
    public List<Order> getWaitOrder(@SessionAttribute long instanceId) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("instance_id", instanceId)
                .eq("stats", 2);
        return orderMapper.selectList(queryWrapper);
    }

    /**
     * 发货
     *
     * @param instanceId 实例id
     * @param orderId    订单id
     * @throws CustomException 当该订单不存在，订单状态不满足时抛出该异常
     */
    @Override
    public void sendGoods(long instanceId, long orderId) throws CustomException {
        Order order = get(instanceId, orderId);
        if (order == null) {
            //找不到该订单
            throw new CustomException(CustomExceptionType.ORDER_NOT_FOUND_ERROR, "找不到");
        }
        if (order.getStats() != 2) {
            //非已完成拣货不允许发货
            throw new CustomException(CustomExceptionType.OPERATION_NOT_ALLOW, "非完成拣货，不允许发货");
        }
        order.setStats(3);
        order.setSendTime(LocalDateTime.now());
        orderMapper.updateById(order);
    }

    /**
     * 用于删除订单
     *
     * @param instanceId 实例id
     * @param orderId    订单id
     * @throws CustomException 当订单不存在，订单非未处理时抛出该异常
     */
    @Override
    public void delete(long instanceId, long orderId) throws CustomException {
        Order order = get(instanceId, orderId);
        if (order == null) {
            //订单不存在
            throw new CustomException(CustomExceptionType.ORDER_NOT_FOUND_ERROR, "找不到该订单");
        }
        if (order.getStats() != 0) {
            //订单非未处理
            throw new CustomException(CustomExceptionType.OPERATION_NOT_ALLOW, "订单已进入拣货出库流程");
        }
        QueryWrapper<OrderProduct> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("instance_id", instanceId)
                .eq("order_id", order.getId());
        //获取涉及订单商品明细
        List<OrderProduct> orderProductList = orderProductMapper.selectList(queryWrapper);
        //获取涉及商品实体
        List<Product> productList = productMapper.getFromIdList(instanceId, orderProductList.stream().map(OrderProduct::getProductId).collect(Collectors.toList()));
        //转化商品id-OrderProduct Map
        Map<Long, OrderProduct> orderProductMap = orderProductList.stream().collect(Collectors.toMap(OrderProduct::getProductId, Function.identity()));
        for (Product item : productList) {
            item.setUnsell(item.getUnsell() + orderProductMap.get(item.getId()).getCount());
        }
        //更新商品列表
        productMapper.updateList(productList);
        //删除订单详情
        QueryWrapper<OrderProduct> orderProductQueryWrapper = new QueryWrapper<>();
        orderProductQueryWrapper.eq("order_id", order);
        orderProductMapper.delete(queryWrapper);
        //删除订单
        orderMapper.deleteById(orderId);
    }

    /**
     * 用于处理拣货
     *
     * @param instanceId  实例id
     * @param userId      用户id
     * @param pickWrapper 拣货Wrapper
     * @throws CustomException 当拣货数量超过需求事抛出该异常
     */
    @Override
    public void pickProduct(long instanceId, Long userId, PickWrapper pickWrapper) throws CustomException {
        //从Wrapper中获取数据
        long orderId = pickWrapper.getOrderId();
        List<PickedProduct> pickedProductList = pickWrapper.getProductList();
        //IO列表
        List<Io> ioList = new ArrayList<>();
        //获取未完成拣货的OrderProduct
        List<OrderProduct> orderProductList = orderProductMapper.getUnpick(instanceId, orderId);
        Map<Long, OrderProduct> orderProductMap = orderProductList.stream().collect(Collectors.toMap(OrderProduct::getProductId, Function.identity()));
        for (PickedProduct item : pickedProductList) {
            if (item.getCount() > (orderProductMap.get(item.getProductId()).getCount() - orderProductMap.get(item.getProductId()).getPickCount())) {
                //拣货数量过多
                throw new CustomException(CustomExceptionType.PICK_MORE_THAN_REQUIRE, "拣货数量超过订单需求");
            }
            //设置拣货后数量
            orderProductMap.get(item.getProductId()).setPickCount(orderProductMap.get(item.getProductId()).getPickCount() + item.getCount());
            if (orderProductMap.get(item.getProductId()).getCount().equals(orderProductMap.get(item.getProductId()).getPickCount())) {
                //该商品完成拣货
                orderProductMap.get(item.getProductId()).setStats(2);
            }
            //构建IO记录
            Io io = new Io(null, LocalDateTime.now(), 1, item.getRackId(), item.getProductId(), item.getCount(), userId, null, instanceId);
            ioList.add(io);
        }
        //插入与更新数据
        ioMapper.insertList(ioList);
        orderProductList = new ArrayList<>(orderProductMap.values());
        orderProductMapper.updateList(orderProductList);
        //检查该订单是否完成拣货
        boolean orderFinishFlag = true;
        for (OrderProduct item : orderProductList) {
            if (item.getStats() == 1) {
                orderFinishFlag = false;
                break;
            }
        }
        if (orderFinishFlag) {
            //订单完成拣货
            Order order = get(instanceId, orderId);
            order.setStats(2);
            orderMapper.updateById(order);
        }
    }

    /**
     * 获得订单详情项
     *
     * @param instanceId     实例id
     * @param orderProductId 订单详情项id
     * @return OrderProduct
     */
    @Override
    public OrderProduct getOrderProduct(long instanceId, long orderProductId) {
        QueryWrapper<OrderProduct> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("instance_id", instanceId)
                .eq("id", orderProductId);
        return orderProductMapper.selectOne(queryWrapper);
    }

    /**
     * 用于修改订单详情项
     *
     * @param instanceId   实例id
     * @param orderProduct 商品详情实体
     * @throws CustomException 当修改后商品数小于0，订单详细项不存在，修改后商品数值小于已拣货，订单不存在，商品不存在，购买数量小于可出售数量时抛出异常
     */
    @Override
    public void updateOrderProduct(long instanceId, OrderProduct orderProduct) throws CustomException {
        OrderProduct orderProductData = getOrderProduct(instanceId, orderProduct.getId());
        if (orderProduct.getCount() <= 0) {
            //修改后商品数小于0
            throw new CustomException(CustomExceptionType.OPERATION_NOT_ALLOW, "商品数量不得小于等于0");
        }
        if (orderProductData == null) {
            //订单详细项不存在
            throw new CustomException(CustomExceptionType.ORDER_PRODUCT_NOT_FOUND, "找不到该订单详情项");
        }
        if (orderProductData.getPickCount() > orderProduct.getCount()) {
            //修改后商品数值小于已拣货
            throw new CustomException(CustomExceptionType.OPERATION_NOT_ALLOW, "修改后商品数小于已拣货数");
        }
        Order order = get(instanceId, orderProduct.getOrderId());
        if (order == null) {
            //订单不存在
            throw new CustomException(CustomExceptionType.ORDER_NOT_FOUND_ERROR, "不存在该订单");
        }
        Product product = productService.get(instanceId, orderProduct.getProductId());
        if (product == null) {
            //商品不存在
            throw new CustomException(CustomExceptionType.PRODUCT_NOT_FOUND_ERROR, "不存在该商品");
        }
        if (product.getUnsell() + orderProductData.getCount() - orderProduct.getCount() < 0) {
            //购买数量小于可出售数量
            throw new CustomException(CustomExceptionType.OPERATION_NOT_ALLOW, "无足够可出售商品");
        }
        //重新计算订单价格
        order.setPrice(order.getPrice() + product.getPrice() * (orderProduct.getCount() - orderProductData.getCount()));
        //重新计算订单明细价格
        orderProductData.setCount(orderProduct.getCount());
        orderProductData.setPrice(orderProductData.getPrice() + product.getPrice() * (orderProduct.getCount() - orderProductData.getCount()));
        orderMapper.updateById(order);
        orderProductMapper.updateById(orderProductData);
    }

    /**
     * 用于向订单中添加商品
     *
     * @param instanceId             实例id
     * @param addOrderProductWrapper Wrapper
     * @throws CustomException 当订单不存在，商品不存在，商品数量不足，原有订单中有该商品，订单已完成拣货时抛出该异常
     */
    @Override
    public void addOrderProduct(long instanceId, AddOrderProductWrapper addOrderProductWrapper) throws CustomException {
        long orderId = addOrderProductWrapper.getOrderId();
        List<OrderProduct> orderProductList = addOrderProductWrapper.getOrderProductList();
        Order order = get(instanceId, orderId);
        if (order == null) {
            //找不到该订单
            throw new CustomException(CustomExceptionType.ORDER_NOT_FOUND_ERROR, "找不到该订单");
        }
        if (order.getStats() > 1) {
            //订单已完成拣货
            throw new CustomException(CustomExceptionType.OPERATION_NOT_ALLOW, "订单已完成拣货，不允许修改");
        }
        //获取订单中的商品id列表
        List<Long> inOrderProductIdList = productMapper.getProductIdFromOrderId(instanceId, orderId);
        //获取添加中的商品实体
        List<Long> productIdList = orderProductList.stream().map(OrderProduct::getProductId).collect(Collectors.toList());//涉及商品实体
        List<Product> productList = productMapper.getFromIdList(instanceId, productIdList);
        if (productList.size() != orderProductList.size()) {
            //存在商品不存在
            throw new CustomException(CustomExceptionType.PRODUCT_NOT_FOUND_ERROR, "找不到该商品");
        }
        Map<Long, Product> productMap = productList.stream().collect(Collectors.toMap(Product::getId, Function.identity()));
        double sum = 0.0;
        for (OrderProduct item : orderProductList) {
            if (productMap.get(item.getProductId()).getUnsell() - item.getCount() < 0) {
                //商品数量不足
                throw new CustomException(CustomExceptionType.PRODUCT_NOT_ENOUGH, "商品数量不足");
            }
            if (inOrderProductIdList.contains(item.getProductId())) {
                //原有订单中有该商品
                throw new CustomException(CustomExceptionType.OPERATION_NOT_ALLOW, "源头订单中存在该商品");
            }
            productMap.get(item.getProductId()).setUnsell(productMap.get(item.getProductId()).getUnsell() - item.getCount());//修改unsell字段
            //设置OrderProduct数据
            double price = item.getCount() * productMap.get(item.getProductId()).getPrice();
            sum += price;
            item.setOrderId(order.getId());
            item.setPrice(price);
            item.setInstanceId(instanceId);
            item.setStats(1);
        }
        //更新数据
        productList = new ArrayList<>(productMap.values());
        productMapper.updateList(productList);
        order.setPrice(order.getPrice() + sum);
        orderMapper.updateById(order);
        orderProductMapper.addList(orderProductList);
    }

    /**
     * 用于删除订单商品项
     *
     * @param instanceId     实例id
     * @param orderProductId 订单商品项
     * @throws CustomException 当找不到该订单详情项，已有拣货时抛出该异常
     */
    @Override
    public void deleteOrderProduct(long instanceId, long orderProductId) throws CustomException {
        OrderProduct orderProduct = getOrderProduct(instanceId, orderProductId);
        if (orderProduct == null) {
            //找不到该订单详情项
            throw new CustomException(CustomExceptionType.ORDER_PRODUCT_NOT_FOUND, "找不到该订单商品");
        }
        if (orderProduct.getStats() > 1 || orderProduct.getPickCount() > 0) {
            //已有拣货
            throw new CustomException(CustomExceptionType.OPERATION_NOT_ALLOW, "已有拣货的商品项不允许删除");
        }
        Order order = get(instanceId, orderProduct.getOrderId());
        order.setPrice(order.getPrice() - orderProduct.getPrice());
        Product product = productService.get(instanceId, orderProduct.getProductId());
        product.setUnsell(product.getUnsell() + orderProduct.getCount());
        orderMapper.updateById(order);
        orderProductMapper.deleteById(orderProduct);
        productMapper.updateById(product);
    }
}
